package BZimmerman.AndroidWars;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import android.graphics.PointF;

public class createMap {
	Random random = new Random(System.currentTimeMillis());
	public int[][] map;
	public int pStartX;
	public int pStartY;
	public int size;
	createMap(int Dim){
		size = Dim;
		//This ensures that the character does not start out on the edges of the map
		pStartX = random.nextInt( Dim-2 );
		pStartY = random.nextInt( Dim-2 );
		pStartX += 1;
		pStartY += 1;
		map = new int [Dim][Dim];
		int plot;
		List<coorObject> trail = new ArrayList<coorObject>();
		Integer[] direction = new Integer[]{0, 1, 2, 3};
		coorObject holder;
		
		for(int y = 0; y< Dim; y++){
			for (int x=0; x<Dim; x++){
				this.map[x][y]= 0;
			}
		}
		
		//This is the point where the player starts
		
		trail.add(new coorObject(pStartX, pStartY));
		
		//Uses kruskal's algorithm to generate a random navigable map
		while (!trail.isEmpty()){
			//Picks a random wall to branch the trail out at
			plot = random.nextInt( trail.size() );
			holder = trail.get(plot);
			this.map[holder.getX()][holder.getY()]= 1;

			// Shuffle the elements in the array
			//This is to make sure that the roads twist, and
			//are not straight corridors after generation
			Collections.shuffle(Arrays.asList(direction));
			//If this direction is in the map
			for (int road : direction){
				if (road == 0){
					if (holder.getX()-1 != 0)
					{
						//If the next cell over in the same direction is not in the maze
						if (checkWall(holder.getX()-2, holder.getY(), Dim)){
							//Mark the cell in between as a transition, and the next cell as part of maze 
							this.map[holder.getX()-1][holder.getY()]= 1;
							this.map[holder.getX()-2][holder.getY()]= 1;
							trail.add(new coorObject(holder.getX()-2, holder.getY()));
						}
					}
				}
				if (road == 1){
					if (holder.getY()+1 != Dim-1)
					{
						if (checkWall(holder.getX(), holder.getY()+2, Dim)){
							this.map[holder.getX()][holder.getY()+1]= 1;
							this.map[holder.getX()][holder.getY()+2]= 1;
							trail.add(new coorObject(holder.getX(), holder.getY()+2));
						}
					}
				}
				if (road == 2){
					if (holder.getX()+1 != Dim-1)
					{
						if (checkWall(holder.getX()+2, holder.getY(), Dim)){
							this.map[holder.getX()+1][holder.getY()]= 1;
							this.map[holder.getX()+2][holder.getY()]= 1;
							trail.add(new coorObject(holder.getX()+2, holder.getY()));
						}
					}
				}
				if (road == 3){
					if (holder.getY()-1 != 0)
					{
						if (checkWall(holder.getX(), holder.getY()-2, Dim)){
							this.map[holder.getX()][holder.getY()-1]= 1;
							this.map[holder.getX()][holder.getY()-2]= 1;
							trail.add(new coorObject(holder.getX(), holder.getY()-2));
						}
					}
				}
			}
			trail.remove(plot);
			
		}
		
		map[pStartX-1][pStartY-1] = 1;
		map[pStartX][pStartY-1] = 1;
		map[pStartX+1][pStartY-1] = 1;
		map[pStartX-1][pStartY] = 1;
		map[pStartX+1][pStartY] = 1;
		map[pStartX-1][pStartY+1] = 1;
		map[pStartX][pStartY+1] = 1;
		map[pStartX+1][pStartY+1] = 1;
		
		//Eliminate walls equal to 5% of total squares
		for(int i = 0; i < ((Dim*Dim)*.05);){
			int selectorX = random.nextInt( Dim-2 );
			int selectorY = random.nextInt( Dim-2 );
			if (map[selectorX+1][selectorY+1] == 0){
				map[selectorX+1][selectorY+1] = 1;
				i++;
			}
		}
		//Develops rivers that require 2 movement points
		developLakes();
		developMountains();
		//developRivers();
	}
	public void developMountains(){
		for(int i = 0; i < ((size*size)*.02);){
			int selectorX = random.nextInt( size-2 );
			int selectorY = random.nextInt( size-2 );
			if (map[selectorX+1][selectorY+1] == 1){
				map[selectorX+1][selectorY+1] = 3;
				i++;
			}
		}
	}
	
	public void developLakes(){
		int selectorX,selectorY;
		//Makes i many lakes
		for(int i = 0; i < size; i++){
			System.out.println("Lake: "+ 1);
			selectorX = random.nextInt( size-2 );
			selectorY = random.nextInt( size-2 );
			while (map[selectorX+1][selectorY+1] == 2){
				selectorX = random.nextInt( size-2 );
				selectorY = random.nextInt( size-2 );
			}
			selectorX+=1;
			selectorY+=1;
			developRivers(new PointF(selectorX,selectorY),25);
			
		}
	}
	public void developRivers(PointF start, int length){
		//up,down,left,right
		ArrayList<PointF> river = new ArrayList<PointF>();
		river.add(start);
		int selectorX,selectorY;
		int breaker;
		//makes i many rivers
		//rivers will keep expanding until they hit water or an edge
		while(river.size()< length){
			selectorX = random.nextInt( 3 );
			selectorY = random.nextInt( 3 );
			if(start.x==0){selectorX = 2;}
			if(start.y==0){selectorY = 2;}
			if(start.x==size-1){selectorX = 0;}
			if(start.y==size-1){selectorY = 0;}
			breaker = 0;
			while (//Breaks after 10 guesses to stop infinite loops
					breaker < 10 &&
					map[(int) start.x+(selectorX-1)][(int) start.y+(selectorY-1)] == 2 &&
					inArray(river,new PointF(start.x+(selectorX-1), start.y+(selectorY-1)))){
				selectorX = random.nextInt( 3 );
				selectorY = random.nextInt( 3 );
				if(start.x==0){selectorX = 2;}
				if(start.y==0){selectorY = 2;}
				if(start.x==size-1){selectorX = 0;}
				if(start.y==size-1){selectorY = 0;}
				breaker++;
			}
			start.x = start.x+(selectorX-1);
			start.y = start.y+(selectorY-1);
			map[(int) start.x][(int) start.y] = 2;
			river.add(new PointF(start.x, start.y));
		}
	}
	public boolean inArray(ArrayList<PointF> array, PointF point){
		for(PointF items: array){
			if(items.equals(point.x,point.y)){
				return true;
			}
		}
		return false;
	}
	//This helps to keep track of the coordinates that are used
	//to make the path on the map
	class coorObject {
		int x;
		int y;
		coorObject(int x, int y){
			this.x = x;
			this.y = y;
		}
		int getX(){
			return x;
		}
		int getY(){
			return y;
		}
	}
	public PointF returnStart(){
		System.out.println(pStartX + " : " + pStartY);
		return new PointF(pStartX,pStartY);
	}
	public boolean checkWall(int X, int Y, int Dim){
		if ((X >= 0) && (Y >= 0) && (X<Dim) && (Y<Dim)){
			if (this.map[X][Y]== 0){
			//The next cell over is not a path nor outside of the map
				return true;
			}
		}
		return false;
	}
	public int returnCellValue(int X, int Y){return this.map[X][Y];}
	public int[][] returnMap(){return this.map;}
}

